home *** CD-ROM | disk | FTP | other *** search
/ Palm Utilities / Palm_Utilities_CD-ROM_2001_2001.iso / files / pim / Hot Date 1.3e / hotdate.exe / hotdate / todo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-10  |  12.6 KB  |  351 lines

  1. /* $Id: todo.c,v 1.46 2000/02/10 14:50:11 chrisf Exp $ */
  2.  
  3. /*
  4. Hot Date - A DatebookDB displayer for the PalmPilot
  5. Copyright (C) 1999 Chris Faherty
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20. */
  21.  
  22. #include <Pilot.h>
  23. #include "callback.h"
  24. #include "hotdateRsc.h"
  25. #include "hotdate.h"
  26. #include "datebook.h"
  27. #include "todo.h"
  28.  
  29. extern struct sPrefsR *PrefsR;
  30. extern Boolean PrefsRdirty;
  31. extern UInt apptTop, apptDays, apptToDoLine;
  32. extern Word apptToDoCategory;
  33. extern DateType apptDate;
  34.  
  35. /*
  36.  * Static function prototypes
  37.  */
  38. static Int ToDoListCompare(ApptInfoPtr a1, ApptInfoPtr a2, Long extra);
  39.  
  40. /*
  41.  * This is the same as ApptListCompare() except that I take into account
  42.  * the user preference for sort order.  Since this only applies to ToDo
  43.  * entries, I made this a separate function.
  44.  */
  45. static Int ToDoListCompare(ApptInfoPtr a1, ApptInfoPtr a2, Long extra)
  46. {
  47.     Int result;
  48.     UInt d1, d2;
  49.     Boolean alwaysbelow=false;
  50.  
  51.     CALLBACK_PROLOGUE
  52.  
  53.     d1 = DateToInt(a1->date);
  54.     d2 = DateToInt(a2->date);
  55.     /*
  56.      * The point here is that we want undated ToDos to always be below the
  57.      * dated ones, regardless of the user selected sort order.
  58.      */
  59.     if (d1 == toDoNoDueDate) {
  60.         d1 = (UInt) 0xFFFFFFFF;
  61.         alwaysbelow = true;
  62.     }
  63.     if (d2 == toDoNoDueDate) {
  64.         d2 = (UInt) 0xFFFFFFFF;
  65.         alwaysbelow = true;
  66.     }
  67.     if (d1 > d2) result = 1; else if (d1 < d2) result = -1; else result = 0;
  68.     if ((PrefsR->ToDoPrefs.sort == '1') && !alwaysbelow) result = -result;
  69.  
  70.     CALLBACK_EPILOGUE
  71.  
  72.     return result;
  73. }
  74.  
  75. /*
  76.  * The way I am doing the ToDos is by adding them along with the Datebook
  77.  * appointments.  Therefore I call AddAppointmentToList() to add a ToDo entry.
  78.  */
  79. UInt GetToDo(DmOpenRef dbP, DateType date, Word days, VoidHand apptLists [],
  80.     UInt counts [])
  81. {
  82.     ApptInfoPtr apptList;
  83.     LineItemPtr LineItem;
  84.     LineItemType tli;
  85.     UInt startDate, endDate;
  86.     DateType tempDate;
  87.     UInt recordNum;
  88.     UInt totalcount=0, currindex=0;
  89.     UInt totalItems;
  90.     UInt origcount;
  91.     UInt i;
  92.     UInt DOW;
  93.     ULong shrunk;
  94.     VoidHand recordH;
  95.     ToDoDBRecordPtr r;
  96.     TimeType notime={-1, -1};
  97.     DateType nodate={-1, -1};
  98.     Word daysm1=days-1;
  99.  
  100.     /*
  101.      * These are used if the item range is specified.  The week is assumed
  102.      * to start on Monday.  We don't bother to compute these if the pref is
  103.      * set for 'All of them' or 'This month' because we use simpler methods
  104.      * for those.
  105.      */
  106.     tempDate = date;
  107.     switch (PrefsR->ToDoPrefs.range) {
  108.     case '3': /* Tomorrow */
  109.         DateAdjust(&tempDate, 1);
  110.         startDate = DateToInt(tempDate);
  111.         endDate = startDate;
  112.         break;
  113.     case '4': /* This week */
  114.     case '5': /* Next week */
  115.     case '7': /* Next 7 days */
  116.     case '8': /* Next 14 days */
  117.     case '9': /* Next 21 days */
  118.     case ':': /* Next 31 days, sorry about the cheezy colon */
  119.         /* find the previous Monday */
  120.         DOW = DayOfWeek(tempDate.month, tempDate.day, tempDate.year+1904);
  121.         /* Check if we need to adjust to the beginning of a week */
  122.         if ((PrefsR->ToDoPrefs.range == '4') ||
  123.             (PrefsR->ToDoPrefs.range == '5')) {
  124.             if (DOW > 1) {
  125.                 DateDaysToDate(DateToDays(tempDate)-(DOW-1), &tempDate);
  126.             } else if (DOW == 0) {
  127.                 /*
  128.                  * If Sunday we'll go back to the previous Monday
  129.                  * as well
  130.                  */
  131.                 DateDaysToDate(DateToDays(tempDate)-6, &tempDate);
  132.             }
  133.         }
  134.         /* Check if we want next week */
  135.         if (PrefsR->ToDoPrefs.range == '5') DateAdjust(&tempDate, 7);
  136.         startDate = DateToInt(tempDate);
  137.         switch (PrefsR->ToDoPrefs.range) {
  138.         case '8': i = 13; break;
  139.         case '9': i = 20; break;
  140.         case ':': i = 30; break;
  141.         default: i = 6;
  142.         }
  143.         DateAdjust(&tempDate, i);
  144.         endDate = DateToInt(tempDate);
  145.         break;
  146.     default: /* Today & company */
  147.         startDate = DateToInt(tempDate);
  148.         endDate = startDate;
  149.     }
  150.     
  151.     totalItems = DmNumRecordsInCategory(dbP, apptToDoCategory);
  152.  
  153.     /*
  154.      * Keep in mind that AddAppointmentToList() is expecting the list to
  155.      * be locked already if it exists.  So we must lock it down.  Don't worry
  156.      * about saving the pointer because it does a MemDeref().  In addition,
  157.      * the list was most likely trimmed and needs to be padded to multiples
  158.      * of 10 items.  But that's taken care of in the function.
  159.      */
  160.     if (apptLists[daysm1]) {
  161.         MemHandleLock(apptLists[daysm1]);
  162.         /*
  163.          * There are probably some packed LineItemType elements already
  164.          * present since the handle exists.  We want to skip over them and
  165.          * add ApptTypeInfo structures, then sort, and then shrink the new
  166.          * elements down to LineItemType as well.
  167.          */
  168.         shrunk = counts[daysm1]*sizeof(LineItemType);
  169.     } else shrunk = 0;
  170.  
  171.     origcount = counts[daysm1]; /* for the sorting at the end */
  172.  
  173.     /*
  174.      * Add a title for the todo listings.  This is drawn in the
  175.      * table callback.  I always add this title even if there are
  176.      * no records because you need it to switch categories.
  177.      */
  178.     if (AddAppointmentToList(&apptLists[daysm1], shrunk,
  179.             counts[daysm1]-origcount, origcount, notime,
  180.             notime, nodate, 0, 2)) {
  181.         /*
  182.          * apptToDoLine is the line number where the ToDos start.  It is
  183.          * linear from the start of the list so we need to add up the previous
  184.          * counts.
  185.          */
  186.         apptToDoLine = 0;
  187.         for (i=0; i < days; i++) apptToDoLine += counts[i];
  188.         counts[daysm1]++;
  189.         totalcount++;
  190.     }
  191.  
  192.     for (recordNum=0; recordNum < totalItems; recordNum++) {
  193.         if ((recordH = DmQueryNextInCategory(dbP, &currindex,
  194.             apptToDoCategory))) {
  195.             r = MemHandleLock(recordH);
  196.             /*
  197.              * Is it dated?  Is it already complete?
  198.              *
  199.              * The past due switch is only going to eliminate items that are
  200.              * past due and beyond the item range.  So you will always see
  201.              * past due items within your item range, but you will only see
  202.              * the rest if you set the switch.  In the case of the "All items"
  203.              * range, you will only see past due items if you set the switch.
  204.              */
  205.             if (
  206.                 /* no due date? */
  207.                 ((PrefsR->ToDoPrefs.nodate == '0') &&
  208.                 (DateToInt(r->dueDate) == toDoNoDueDate)) ||
  209.                 /* completed? */
  210.                 ((PrefsR->ToDoPrefs.done == '0') &&
  211.                 (r->priority & completeFlag)) ||
  212.                 /* past due? */
  213.                 ((DateToInt(r->dueDate) < startDate) &&
  214.                 (PrefsR->ToDoPrefs.pastdue == '0') &&
  215.                 !(r->priority & completeFlag) &&
  216.                 (PrefsR->ToDoPrefs.range == '1'))
  217.                 ) {
  218.                 /* don't show */
  219.             } else {
  220.                 /*
  221.                  * Is it within the proper date range?
  222.                  */
  223.                 if (
  224.                     /* no due date? */
  225.                     (DateToInt(r->dueDate) == toDoNoDueDate) ||
  226.                     /* include past due items? */
  227.                     ((DateToInt(r->dueDate) < startDate) &&
  228.                     (PrefsR->ToDoPrefs.pastdue == '1') &&
  229.                     !(r->priority & completeFlag)) ||
  230.                     /* all of them? */
  231.                     ((PrefsR->ToDoPrefs.range == '1') ||
  232.                     /* current month? */
  233.                     ((PrefsR->ToDoPrefs.range == '6') &&
  234.                     (r->dueDate.month == date.month)) ||
  235.                     /* otherwise check date range */
  236.                     ((DateToInt(r->dueDate) >= startDate) &&
  237.                     (DateToInt(r->dueDate) <= endDate)))
  238.                     ) {
  239.                     /* always put it under the last day; apptLists[daysm1] */
  240.                     if (AddAppointmentToList(&apptLists[daysm1], shrunk,
  241.                         counts[daysm1]-origcount, origcount, notime, notime,
  242.                         r->dueDate, currindex, 1)) {
  243.                         counts[daysm1]++;
  244.                         totalcount++;
  245.                     }
  246.                 }
  247.             }
  248.             MemHandleUnlock(recordH);
  249.             currindex++;
  250.         }
  251.     }
  252.  
  253.     /*
  254.      * This was locked inside AddAppointmentToList, and it is also buffered
  255.      * to 10 positions and must be trimmed.  Also we want to sort the ToDos
  256.      * in the list.
  257.      */
  258.     if (apptLists[daysm1] && (counts[daysm1] > origcount)) {
  259.         /*
  260.          * Get the pointer again.  Yeah I know this sucks having to
  261.          * deref the handle again but I didn't want to have to carry
  262.          * around a pointer.
  263.          */
  264.         MemHandleUnlock(apptLists[daysm1]);
  265.         apptList = MemHandleLock(apptLists[daysm1]);
  266.         apptList = (ApptInfoPtr) (((char *) apptList)+shrunk);
  267.         if ((counts[daysm1]-origcount-1) >= 2) {
  268.             SysInsertionSort(&apptList[1], counts[daysm1]-origcount-1,
  269.                 sizeof(ApptInfoType), (_comparF *) ToDoListCompare, 0L);
  270.         }
  271.         /*
  272.          * Shrink the array down to a more compact structure because we
  273.          * don't need many of the structure elements anymore.
  274.          */
  275.         LineItem = (LineItemPtr) apptList;
  276.         for (i=0; i < (counts[daysm1]-origcount); i++) {
  277.             /*
  278.              * Both LineItem & apptList point to the same spot so make
  279.              * sure to use a temporary holding place when copying.
  280.              */
  281.             tli.recordNum = apptList[i].recordNum;
  282.             tli.startTime = notime;
  283.             tli.date = apptList[i].date;
  284.             LineItem[i] = tli;
  285.         }
  286.         MemHandleUnlock(apptLists[daysm1]);
  287.         MemHandleResize(apptLists[daysm1], counts[daysm1]*sizeof(LineItemType));
  288.     }
  289.  
  290.     return totalcount;
  291. }
  292.  
  293. void SelectCategoryPopup(DmOpenRef dbP, TablePtr table, Word row)
  294. {
  295.     Int curSelection;
  296.     Int newSelection;
  297.     ListPtr lst;
  298.     CharPtr name;
  299.     RectangleType r, r2;
  300.     FormPtr frm;
  301.     
  302.     frm = FrmGetActiveForm();
  303.     lst = FrmGetObjectPtr(frm, FrmGetObjectIndex(frm, listID_todocategories));
  304.  
  305.     /* Unhighlight the row in my table. */
  306.     TblUnhighlightSelection(table);
  307.  
  308.     LstSetPosition(lst, 0, 0);
  309.     
  310.     /* Create a list of categories. */
  311.     CategoryCreateList(dbP, lst, apptToDoCategory, true, true, 1, 0, true);
  312.  
  313.     /* Position the list. */
  314.     TblGetItemBounds(table, row, 0, &r);
  315.     FrmGetObjectBounds(frm, FrmGetObjectIndex(frm, listID_todocategories), &r2);
  316.     LstSetPosition(lst, r.topLeft.x+r.extent.x-r2.extent.x, r.topLeft.y);
  317.  
  318.     /* Display the category list. */
  319.     curSelection = LstGetSelection(lst);
  320.     newSelection = LstPopupList(lst);
  321.  
  322.     /* Was a new category selected? */
  323.     if ((newSelection != curSelection) && (newSelection != -1)) {
  324.         if ((name = LstGetSelectionText(lst, newSelection))) {
  325.             apptToDoCategory = CategoryFind(dbP, name);
  326.             /*
  327.              * Copy the category name into my preferences record and mark
  328.              * it dirty.
  329.              */
  330.             MemSet(PrefsR->todocategory,
  331.                 sizeof(PrefsR->todocategory), 0);
  332.             MemMove(PrefsR->todocategory, name, StrLen(name));
  333.             /*
  334.              * No immediate need to write, so we just flag it for when the
  335.              * program ends.
  336.              */
  337.             PrefsRdirty = true;
  338.             if (PrefsR->ToDoPrefs.gotop == '1') apptTop = apptToDoLine;
  339.             /*
  340.              * This is a quickie regen of the table data.  It only
  341.              * does the ToDo items because that is the only thing
  342.              * that has changed and we want it to work quickly.
  343.              */
  344.             MainFormLoadTable(frm, 3, apptTop, apptDate, apptDays);
  345.             ShowScrollArrows(frm);
  346.         }
  347.     }
  348.  
  349.     CategoryFreeList(dbP, lst, false, false);
  350. }
  351.